#pragma once

#include "znx_defs.h"
#include "znx_atomic.h"
#include "znx_spinlock.h"


#define ZNX_MEM_ITEM_MAGIC                          0xFA5CFFFA
#define ZNX_ALIGNED_MEM_ITEM_MAGIC                  0xFA5CFFAF
#define ZNX_MEM_4K_ALIGNMENT                        (1u << 12)
#define ZNX_MEM_MAX_ALLOC_SIZE                      (1u << 31)


typedef struct {
    uint32_t                magic;
    size_t                  size;
    void                    *next;  /* for free list */
} znx_mem_item_head_t;


typedef struct {
    uint32_t            magic;
    size_t              size;
    void                *next;  /* for free list */
    void                *ptr;   /* reserve a ptr space */
} znx_aligned_mem_item_head_t;


#define ZNX_4KALIGNED_MEM_ITEM_OFFSET                            \
    ((ZNX_MEM_4K_ALIGNMENT - 1) + sizeof(znx_aligned_mem_item_head_t))

#define ZNX_4KALIGNED_MEM_ITEM_PTR(item)                         \
    ((void *)(((size_t)item + (size_t)ZNX_4KALIGNED_MEM_ITEM_OFFSET) & ~((size_t)ZNX_MEM_4K_ALIGNMENT - 1)))


typedef struct {
    znx_spinlock_t          lock;
    int64_t                 space_size;
    int64_t                 water_level;
    int64_t                 count;
    int64_t                 used;
    void                    *head;
} znx_mem_freelist_t;


typedef enum {
    ZNX_FREELIST_64_MODE        = 0,
    ZNX_FREELIST_128_MODE       = 1,
    ZNX_FREELIST_256_MODE       = 2,
    ZNX_FREELIST_512_MODE       = 3,
    ZNX_FREELIST_1K_MODE        = 4,
    ZNX_FREELIST_2K_MODE        = 5,
    ZNX_FREELIST_4K_MODE        = 6,
    ZNX_FREELIST_8K_MODE        = 7,
    ZNX_FREELIST_16K_MODE       = 8,
    ZNX_FREELIST_32K_MODE       = 9,
    ZNX_FREELIST_64K_MODE       = 10,
    ZNX_FREELIST_128K_MODE      = 11,
    ZNX_FREELIST_256K_MODE      = 12,
    ZNX_FREELIST_512K_MODE      = 13,
    ZNX_FREELIST_1M_MODE        = 14,
    ZNX_FREELIST_2M_MODE        = 15,
    ZNX_FREELIST_4M_MODE        = 16,
    ZNX_FREELIST_8M_MODE        = 17,
    ZNX_FREELIST_MODE_END       = 18
} znx_mem_freelist_mode_t;


typedef struct {
    znx_mem_freelist_t       lists[ZNX_FREELIST_MODE_END];
    znx_bool_t               inited;
} znx_mem_freelists_t;


static inline uint32_t
znx_mem_freelist_mode_to_size(int mode)
{
    assert(mode >= 0 &&
        mode < ZNX_FREELIST_MODE_END);
    return (uint32_t)(1 << (mode + 6));
}


typedef enum {
    MEM_4KALIGNED_FREELIST_4K_MODE          = 0,
    MEM_4KALIGNED_FREELIST_8K_MODE          = 1,
    MEM_4KALIGNED_FREELIST_16K_MODE         = 2,
    MEM_4KALIGNED_FREELIST_32K_MODE         = 3,
    MEM_4KALIGNED_FREELIST_64K_MODE         = 4,
    MEM_4KALIGNED_FREELIST_128K_MODE        = 5,
    MEM_4KALIGNED_FREELIST_256K_MODE        = 6,
    MEM_4KALIGNED_FREELIST_512K_MODE        = 7,
    MEM_4KALIGNED_FREELIST_1M_MODE          = 8,
    MEM_4KALIGNED_FREELIST_2M_MODE          = 9,
    MEM_4KALIGNED_FREELIST_4M_MODE          = 10,
    MEM_4KALIGNED_FREELIST_8M_MODE          = 11,
    MEM_4KALIGNED_FREELIST_MODE_END         = 12           
} znx_4kaligned_mem_freelist_mode_t;


typedef struct {
    znx_mem_freelist_t      lists[MEM_4KALIGNED_FREELIST_MODE_END];
    znx_bool_t              inited;
} znx_4kaligned_mem_freelists_t;


static inline uint32_t
znx_4kaligned_mem_freelist_mode_to_size(int mode)
{
    assert(mode >= 0 &&
        mode < MEM_4KALIGNED_FREELIST_MODE_END);
    return (uint32_t)(1 << (mode + 12));
}



// interface
void znx_mem_init(int64_t water_level);

void *znx_mem_alloc(size_t size);

void znx_mem_free(void *ptr);

static inline void *
znx_mem_calloc(size_t size)
{
    void *ptr = znx_mem_alloc(size);
    bzero(ptr, size);
    return ptr;
}

void znx_mem_status_report(char *buf, size_t buf_size);

void znx_mem_clean();



void znx_4kaligned_mem_init(int64_t water_level);

void *znx_4kaligned_mem_alloc(size_t size);

void znx_4kaligned_mem_free(void *ptr);

void znx_4kaligned_mem_status_report(char *buf, size_t buf_size);

void znx_4kaligned_mem_clean();

